import {
  _decorator,
  Color,
  Component,
  EventTouch,
  Label,
  Node,
  ParticleSystem2D,
  Rect,
  sp,
  Sprite,
  SpriteFrame,
  TiledMapAsset,
  tween,
  Tween,
  UIOpacity,
  UITransform,
  v2,
  v3,
  Vec2,
  Vec3,
  view,
} from 'cc';
import { PoolFactory } from '../../Basic/Component/PoolFactory';
import { EventType, PoolElementType } from '../Config/GameEnum';
import { GameModel } from './GameModel';
import { GridItem } from './GridItem';
import { GameColor } from '../Model/GameColor';
import { MathUtil } from '../../Util/MathUtil';
import { EventManager } from '../../Basic/Manager/EventManager';
import { LoadingManager } from '../../Basic/Manager/LoadingManager';
import { LoadingBundle, SoundCode } from '../../Basic/Config/BaseEnum';
import { CallBackHandler } from '../../Basic/Model/PoolObj/CallBackHandler';
import { StringUtil } from '../../Util/StringUtil';
import { DataMgr, GameData, PlayerData } from '../../Basic/Manager/DataManager';
import { ColorItem } from './ColorItem';
import { AudioManager } from '../../Basic/Manager/AudioManager';
import { AniScript } from '../Ani/AniScript';
import { SettlementModel } from '../Settlement/SettlementModel';
import { Tool } from '../../Util/Tool';
import { MultiPlatform } from '../../Basic/Model/Platform/MultiPlatform';
import { GameParams, PlayerParams } from '../../Basic/Config/DataConfig';
import { GEEvent, GravityModel } from '../../Basic/Model/SDK/GravityModel';
const { ccclass, property } = _decorator;

@ccclass('CellMachine')
export class CellMachine extends Component {
  @property(Sprite)
  machineBg: Sprite;
  @property(Node)
  cellParent: Node;
  @property(Node)
  ectParent: Node;
  @property(Node)
  flyParent: Node;
  @property(Node)
  bornPos: Node;
  @property(PoolFactory)
  poolFac: PoolFactory;

  /** 当前棋盘行数 */
  row: number;
  /** 当前棋盘列数 */
  col: number;
  /** 当前格子 */
  curSingleItem: GridItem;
  /** 当前格子 */
  nextSingleItem: GridItem;
  /** 当前格子 */
  boxPropItem: GridItem;
  /** 棋盘格子 */
  gridItems: GridItem[];
  /** 上一次的下标 */
  lastIndex: number;
  /** 当前可释放状态 */
  releaseEnable: boolean;

  notShowCount: number;

  prop1Enable: boolean;
  /** 固定id下标 */
  fixationIndex: number;

  canBoxArr: GridItem[];
  removeArr: ColorItem[][];
  adUnlockItem: number[];
  colArr: number[];
  flyPos: { color: string; wPos: Vec3 }[];
  flyTimer = this.createFlyColor.bind(this);
  // adTimer = this.onAd.bind(this);

  combeCount: number;
  combeTxt: string;
  /** 检测间隔(单位:s) */
  checkSpace: number = 0.2;
  /** 发射速度(单位:s) */
  shootSpeed: number = 0.3;
  /** 消除速度(单位:s) */
  cleanSpeed: number = 0.5;
  /** 形变速度(单位:s) */
  shapeChange: number = 0.4;
  /** 位移速度(单位:s) */
  moveSpeed: number = 0.2;

  curTime: number;
  guideItem: Node;
  guideStep: number;
  guideIndexArr: number[];

  propItem: boolean;
  tempColor: GameColor[];

  constructor() {
    super();
    this.row = 0;
    this.col = 0;
    this.curSingleItem = null;
    this.nextSingleItem = null;
    this.gridItems = [];
    this.lastIndex = -1;
    this.releaseEnable = true;
    this.notShowCount = 0;
    this.prop1Enable = false;
    this.fixationIndex = 0;
    this.canBoxArr = [];
    this.removeArr = [];
    this.flyPos = [];
    this.colArr = [];
    this.tempColor = [];
  }

  protected onEnable(): void {
    EventManager.Ins().register(EventType.CREATE_FLY_COLOR, this.createFlyColor, this);
    // EventManager.Ins().register(EventType.AD_GRID, this.adTimer, this);
  }

  /** 初始化机器 */
  initMachine(row: number, col: number) {
    this.row = row;
    this.col = col;
    this.combeCount = 0;
    this.combeTxt = '';
    this.fixationIndex = 0;
    this.adUnlockItem = [];
    this.removeArr = [];
    this.colArr = [];
    this.propItem = false;
    this.curSingleItem = null;
    this.nextSingleItem = null;
    this.boxPropItem = null;
    this.guideItem = null;
    this.guideStep = 0;
    this.guideIndexArr = GameModel.Ins().curLevelData.guidePos;
    // const gameLevel = DataMgr.gameParams.get(GameParams.gameLevel);
    // const gameLevel = 2;
    // if (gameLevel < 3) {
    // 读取配置关卡
    const func: CallBackHandler = CallBackHandler.pop();
    func.callBack = (res: TiledMapAsset[]) => {
      if (res === undefined || res.length <= 0) return;
      // 1.解析数据
      const reg = /<data[^>]*>[^<]*<\/data>/gi;
      let ret = res[0].tmxXmlStr.match(reg).shift();
      ret = ret.replace(/(<\/?data.*?>)/gi, '');
      ret = ret.replace(/\s/gi, '');
      const retArr = StringUtil.strSplitMore(ret, Number, ',');
      const itemDataArr: number[][] = [];
      for (let i = 0; i < retArr.length; i += this.col * 2) {
        const arr = [];
        for (let j = i; j < i + this.col * 2; j++) {
          arr.push(retArr[j] - 1);
        }
        itemDataArr.push(arr);
      }
      const dataArr: number[][] = [];
      for (let i = 0; i < itemDataArr.length; i += 2) {
        for (let j = 0; j < this.col; j++) {
          const arr = [...itemDataArr[i].splice(0, 2), ...itemDataArr[i + 1].splice(0, 2)];
          dataArr.push(arr);
        }
      }

      // 2.封装数据
      const colorData: GameColor[][] = [];
      dataArr.forEach((data) => {
        const arr: GameColor[] = [];
        let isEmpty = true;
        data.forEach((id) => {
          if (id != -1) isEmpty = false;
        });

        if (isEmpty) {
          arr.push(new GameColor(`-1`, ...[0, 1, 2, 3]));
        } else {
          arr.push(...this.encapsulationData(data));
        }
        colorData.push(arr);
      });
      this.applyData(colorData);
      this.createSingleItem();
      this.createNextItem();
      this.createBoxPropItem();
    };
    func.target = this;
    const mapArr = [];
    GameModel.Ins().curLevelData.map.forEach((element) => {
      const reg = /\d+/g;
      mapArr.push(Number(element.match(reg)[0]));
    });
    LoadingManager.Ins().loadResByBundle<TiledMapAsset>(LoadingBundle.PublicBundle, [`tilemap/level${MathUtil.randomIntegerBetween(mapArr[0], mapArr[1])}`], func);
  }

  /** 封装数据 */
  encapsulationData(data: number[]) {
    const arr: GameColor[] = [];
    const colorList = DataMgr.tables.TbColor.getDataList();
    for (let i = 0; i < data.length; i++) {
      let index = -1;
      const ret = colorList.filter((color) => {
        return color.tileId === data[i];
      });
      const id = ret[0].id;
      arr.forEach((color, j) => {
        if (color.colorId === id) {
          index = j;
        }
      });

      if (index != -1 && ((arr[index].posArr[0] === 0 && i != 3) || (arr[index].posArr[0] === 1 && i != 2) || (arr[index].posArr[0] === 2 && i == 3) || arr[index].posArr.length === 3)) {
        arr[index].posArr.push(i);
      } else {
        arr.push(new GameColor(id, ...[i]));
      }
    }
    return arr;
  }

  /** 应用数据 */
  applyData(colorArr: GameColor[][]) {
    const itemSize = GameModel.Ins().itemSize;
    for (let j = 0; j < this.col; j++) {
      for (let i = 0; i < this.row; i++) {
        const item = this.poolFac.pop(PoolElementType.GRID_ITEM, 'maingame/game', 'GridItem');
        item.active = true;
        item.setScale(1, 1);
        const script = item.getComponent(GridItem);
        script.setIndex(j, i);
        script.setData(colorArr[i * this.col + j]);
        // script.selfBtn.active = false;
        script.refrechColor();
        script.resetDestory();
        this.cellParent.addChild(item);
        this.gridItems.push(script);
        item.setPosition((-(this.col - 1) / 2) * itemSize.width + j * itemSize.width, ((this.row - 1) / 2) * itemSize.width - i * itemSize.width + 13 / 2);
      }
    }
  }

  /** 复活 */
  revive() {
    GameModel.Ins().adCount++;
    DataMgr.changePlayerAttr(PlayerParams.adCount, 1);
    // GravityModel.I.userSet({ accuAds: PlayerData.get(PlayerParams.adCount) });
    // GravityModel.I.track(GEEvent.AD_SHOW_END, { adPosition: `看广告复活` });
    GameModel.Ins().reviveCount--;
    if (GameModel.Ins().curGridCount >= 0) {
      GameModel.Ins().curGridCount += 10;
      GameModel.Ins().propMac.refreshGridCount();
    }
    GameModel.Ins().startTimer();
    this.curSingleItem.node.active = false;
    this.checkProp(null, true);
  }

  /** 重置机器 */
  resetMachine() {
    EventManager.Ins().unRegister(EventType.CREATE_FLY_COLOR, this.createFlyColor);
    // EventManager.Ins().unRegister(EventType.AD_GRID, this.adTimer);
    while (this.gridItems.length) {
      const item = this.gridItems.pop();
      item.reset();
      this.poolFac.push(item.node);
    }
    this.gridItems = [];
    this.curSingleItem.reset();
    this.nextSingleItem.reset();
    this.poolFac.push(this.curSingleItem.node);
    this.poolFac.push(this.nextSingleItem.node);
    this.poolFac.push(this.boxPropItem.node);
    if (this.guideItem != null) this.poolFac.push(this.guideItem);
    this.curSingleItem = null;
    this.nextSingleItem = null;
    this.boxPropItem = null;
    this.guideItem = null;
    this.guideStep = 0;
    this.guideIndexArr = [];
    this.lastIndex = -1;
    this.releaseEnable = true;
    this.notShowCount = 0;
    this.prop1Enable = false;
    this.row = 0;
    this.col = 0;
  }

  getNextColor() {
    const colorDataList = DataMgr.tables.TbColor.getDataList();
    const colorDatas: GameColor[] = [];
    if (this.fixationIndex < GameModel.Ins().curLevelData.preColor.length) {
      const tempData = GameModel.Ins().curLevelData.preColor[this.fixationIndex];
      const tempData1 = [];
      tempData.forEach((color) => {
        const ret = colorDataList.filter((c) => c.id === color);
        tempData1.push(ret.length > 0 ? ret[0].tileId : -1);
      });
      colorDatas.push(...this.encapsulationData(tempData1));
      this.fixationIndex++;
    } else {
      colorDatas.push(...GameModel.Ins().getItemData());
      const colorArr = GameModel.Ins().orderMac.getVisitorColor();
      let ret = true;
      colorDatas.forEach((data) => {
        if (colorArr.indexOf(data.colorId) !== -1) {
          ret = false;
        }
      });

      if (ret) this.notShowCount++;
      else this.notShowCount = 0;
      /** 连续5次未出现需求的颜色 下一次必现 */
      if (this.notShowCount > 3 && colorArr.length > 0) {
        console.log('visitor color', colorArr.toString());
        const id = colorArr[MathUtil.randomIntegerBetween(0, colorArr.length)];
        if (id != '') colorDatas[MathUtil.randomIntegerBetween(0, colorDatas.length)].colorId = id;
        this.notShowCount = 0;
      }
    }

    if (GameModel.Ins().curGridCount == 0) {
      colorDatas.splice(0);
      colorDatas.push(new GameColor('-1', 0, 1, 2, 3));
    }
    const s = [];
    colorDatas.forEach((element) => {
      s.push(element.colorId);
    });
    console.log(s.toString());
    return colorDatas;
  }

  /** 创建单个对象 */
  createSingleItem() {
    if (this.curSingleItem === null) {
      const item = this.poolFac.pop(PoolElementType.GRID_ITEM, 'maingame/game', 'GridItem');
      this.curSingleItem = item.getComponent(GridItem);
      this.curSingleItem.setIndex(-1, -1);
      this.cellParent.addChild(item);
      this.curSingleItem.node.active = false;
    }

    const func2 = () => {
      this.prop1Enable = false;
      this.showGuide(true);
      this.releaseEnable = true;
      GameModel.Ins().propMac.showAllItem(true);
    };
    Tween.stopAllByTarget(this.curSingleItem.node);
    if (!this.curSingleItem.node.active && this.nextSingleItem != null) {
      this.curSingleItem.reset();
      this.curSingleItem.setIndex(-1, -1);
      this.curSingleItem.node.setPosition(this.bornPos.getPosition().clone());
      // this.curSingleItem.selfBtn.active = false;
      if (this.nextSingleItem.isEmpty && GameModel.Ins().curGridCount != 0) {
        this.nextSingleItem.setData(this.getNextColor());
        this.nextSingleItem.node.setPosition(-1, -1);
        return this.createSingleItem();
      } else if (this.prop1Enable) {
        this.curSingleItem.setData([...this.tempColor]);
        this.curSingleItem.node.active = true;
        this.curSingleItem.refrechColor(true);
        this.curSingleItem.resetDestory();

        tween(this.curSingleItem.node)
          .to(0.5, { scale: v3(1, 1, 1) }, { easing: 'backOut' })
          .call(func2.bind(this))
          .start();
        return;
      }

      if (GameModel.Ins().curGridCount > 0 && !this.prop1Enable) {
        GameModel.Ins().curGridCount--;
        GameModel.Ins().propMac.refreshGridCount();
      }

      this.curSingleItem.node.setScale(0.5, 0.5);
      Tween.stopAllByTarget(this.nextSingleItem.node);
      let pos = this.curSingleItem.node.getWorldPosition();
      pos = this.nextSingleItem.node.parent.getComponent(UITransform).convertToNodeSpaceAR(pos);
      const func = () => {
        this.curSingleItem.setData([...this.nextSingleItem.colorData]);
        this.curSingleItem.node.active = true;
        this.curSingleItem.refrechColor(true);
        this.curSingleItem.resetDestory();
        this.nextSingleItem.setData(this.getNextColor());
        this.nextSingleItem.node.setPosition(-1, -1);
        this.nextSingleItem.refrechColor();
        if (GameModel.Ins().curGridCount === 0 && this.curSingleItem.isEmpty) {
          SettlementModel.Ins().isPass = false;
          SettlementModel.Ins().Show();
        }
      };

      tween(this.nextSingleItem.node).to(0.19, { position: pos }).call(func.bind(this)).start();
      tween(this.curSingleItem.node)
        .delay(0.2)
        .to(0.3, { scale: v3(1, 1, 1) }, { easing: 'backOut' })
        .call(func2.bind(this))
        .start();
    } else if (!this.curSingleItem.node.active) {
      if (this.prop1Enable) {
        this.curSingleItem.setData([...this.tempColor]);
        this.curSingleItem.node.active = true;
        this.curSingleItem.refrechColor(true);
        this.curSingleItem.resetDestory();
        tween(this.curSingleItem.node)
          .to(0.5, { scale: v3(1, 1, 1) }, { easing: 'backOut' })
          .call(func2.bind(this))
          .start();
        return;
      }

      if (GameModel.Ins().curGridCount > 0) {
        GameModel.Ins().curGridCount--;
        GameModel.Ins().propMac.refreshGridCount();
      }
      this.curSingleItem.reset();
      this.curSingleItem.setIndex(-1, -1);
      this.curSingleItem.setData(this.getNextColor());
      // this.curSingleItem.selfBtn.active = false;
      this.curSingleItem.refrechColor();
      this.curSingleItem.resetDestory();
      this.curSingleItem.node.setPosition(this.bornPos.getPosition().clone());
      this.curSingleItem.node.active = true;
      this.curSingleItem.node.setScale(0.5, 0.5);
      tween(this.curSingleItem.node)
        .to(0.5, { scale: v3(1, 1, 1) }, { easing: 'backOut' })
        .call(func2.bind(this))
        .start();
    } else {
      this.prop1Enable = false;
      this.showGuide(true);
      this.releaseEnable = true;
      GameModel.Ins().propMac.showAllItem(true);
    }
  }

  /** 创建单个对象 */
  createNextItem() {
    if (this.nextSingleItem === null) {
      const item = this.poolFac.pop(PoolElementType.GRID_ITEM, 'maingame/game', 'GridItem');
      this.nextSingleItem = item.getComponent(GridItem);
      this.nextSingleItem.setIndex(-1, -1);
      GameModel.Ins().propMac.cellItem.getChildByName('item').addChild(item);
      this.nextSingleItem.node.active = true;
    }
    this.nextSingleItem.reset();
    this.nextSingleItem.setIndex(-1, -1);
    this.nextSingleItem.setData(this.getNextColor());
    // this.nextSingleItem.selfBtn.active = false;
    this.nextSingleItem.refrechColor();
    this.nextSingleItem.resetDestory();
    this.nextSingleItem.node.setPosition(0, 5);
    this.nextSingleItem.node.setScale(0.7, 0.7);
  }

  createBoxPropItem() {
    if (this.boxPropItem === null) {
      const item = this.poolFac.pop(PoolElementType.GRID_ITEM, 'maingame/game', 'GridItem');
      this.boxPropItem = item.getComponent(GridItem);
      this.boxPropItem.setIndex(-1, -1);
      GameModel.Ins().orderMac.coinParent.addChild(item);
      this.boxPropItem.node.active = false;
    }
    this.boxPropItem.reset();
    this.boxPropItem.setIndex(-1, -1);
    this.boxPropItem.setData([new GameColor('item_box', 0, 1, 2, 3)]);
    // this.boxPropItem.selfBtn.active = false;
    this.boxPropItem.refrechColor();
    this.boxPropItem.resetDestory();
    this.boxPropItem.node.setPosition(0, 0);
  }

  showBoxPropItem(isShow: boolean, pos?: Vec2) {
    if (isShow) {
      let newPos = new Vec3(pos.x, pos.y);
      newPos = GameModel.Ins().orderMac.coinParent.getComponent(UITransform).convertToNodeSpaceAR(newPos);
      newPos.y += GameModel.Ins().itemSize.height;
      const rectArr: { rect: Rect; item: GridItem }[] = [];
      this.gridItems.forEach((i) => {
        if (i.isEmpty || i.isBox || i.isCrack || i.isDisable) return;
        const r = new Rect();
        const localPos = i.node.getPosition();
        r.x = localPos.x - GameModel.Ins().itemSize.width / 2;
        r.y = localPos.y - GameModel.Ins().itemSize.height / 2;
        r.width = GameModel.Ins().itemSize.width;
        r.height = GameModel.Ins().itemSize.height;
        rectArr.push({ rect: r, item: i });
      });

      const retArr = rectArr.filter((obj) => {
        return obj.rect.contains(v2(newPos.x, newPos.y));
      });

      if (retArr.length > 0) {
        let tempPos = retArr[0].item.node.getWorldPosition();
        tempPos = GameModel.Ins().orderMac.coinParent.getComponent(UITransform).convertToNodeSpaceAR(tempPos);
        this.boxPropItem.node.setPosition(tempPos);
      } else {
        this.boxPropItem.node.setPosition(newPos);
      }
      this.boxPropItem.colorParent.getComponent(UIOpacity).opacity = 196;
      this.boxPropItem.node.active = true;
    } else {
      this.boxPropItem.node.active = false;
    }
  }
  /** 释放打包盒道具 */
  releaseBoxProp(pos: Vec2) {
    this.showBoxPropItem(false);
    let newPos = new Vec3(pos.x, pos.y);
    newPos = GameModel.Ins().orderMac.coinParent.getComponent(UITransform).convertToNodeSpaceAR(newPos);
    newPos.y += GameModel.Ins().itemSize.height;
    // this.boxPropItem.node.setPosition(newPos);

    const rectArr: { rect: Rect; item: GridItem }[] = [];
    this.gridItems.forEach((i) => {
      if (i.isEmpty || i.isBox || i.isCrack || i.isDisable) return;
      const r = new Rect();
      const localPos = i.node.getPosition();
      r.x = localPos.x - GameModel.Ins().itemSize.width / 2;
      r.y = localPos.y - GameModel.Ins().itemSize.height / 2;
      r.width = GameModel.Ins().itemSize.width;
      r.height = GameModel.Ins().itemSize.height;
      rectArr.push({ rect: r, item: i });
    });

    const retArr = rectArr.filter((obj) => {
      return obj.rect.contains(v2(newPos.x, newPos.y));
    });

    Tween.stopAllByTarget(this.boxPropItem.node);
    if (retArr.length > 0) {
      this.prop1Enable = true;
      retArr[0].item.onClickItem();
      DataMgr.changeGameAttr(GameParams.item_box, -1);
      GameModel.Ins().propMac.refreshAllProp();
    } else {
      EventManager.Ins().emit(EventType.SHOW_MOUSE_CTRL, true);
    }
    // EventManager.Ins().emit(EventType.SHOW_MOUSE_CTRL, true);
  }

  useProp(propId: string) {
    if (!this.releaseEnable) return false;
    switch (propId) {
      case 'item_box' /** 蛋糕盒 */:
        if (this.checkColorItem() <= 0) {
          console.log(`没有可打包的布丁了`);
          return false;
        }
        this.prop1Enable = true;
        // this.gridItems.forEach((item) => {
        //   item.selfBtn.active = true;
        // });
        GameModel.Ins().propMac.showAllItem(false);
        // this.gridItems.
        EventManager.Ins().emit(EventType.SHOW_MOUSE_CTRL, false);
        return true;
      // case 2 /** 彩色蛋糕 */:
      //   this.curSingleItem.setData([new GameColor('201', ...[0, 1, 2, 3])]);
      //   break;
      case 'item_scoop2' /** 蛋糕铲(列) */:
        this.prop1Enable = true;
        this.tempColor = this.curSingleItem.colorData.splice(0);
        this.curSingleItem.setData([new GameColor('item_scoop2', ...[0, 1, 2, 3])]);
        break;
      case 'item_scoop1' /** 蛋糕铲(行) */:
        this.prop1Enable = true;
        this.tempColor = this.curSingleItem.colorData.splice(0);
        this.curSingleItem.setData([new GameColor('item_scoop1', ...[0, 1, 2, 3])]);
        break;
      // case 5 /** 左转 */:
      //   this.rotateGridItem(this.curSingleItem, true);
      //   break;
      // case 6 /** 右转 */:
      //   this.rotateGridItem(this.curSingleItem, false);
      //   break;
    }
    this.curSingleItem.refrechColor();
    return true;
  }

  checkColorItem() {
    const item = this.gridItems.filter((item) => {
      return !item.isEmpty && !item.isBox && !item.isCrack && !item.isDisable;
    });
    return item.length;
  }

  /** 旋转item */
  rotateGridItem(item: GridItem, isLeft: boolean) {
    if (item.isEmpty) return;
    const data = [...item.colorData];
    const tempArr = [];
    data.forEach((d) => {
      d.posArr.forEach((i) => {
        tempArr[i] = d.colorId;
      });
    });

    const indexArr = isLeft ? [1, 3, 0, 2] : [2, 0, 3, 1];
    const retArr = [];
    for (let i = 0; i < indexArr.length; i++) {
      retArr.push(tempArr[indexArr[i]]);
    }
    const arr: GameColor[] = [];
    retArr.forEach((id, tempIndex) => {
      let ret = -1;
      arr.forEach((color, arrIndex) => {
        if (color.colorId == id) {
          if (color.posArr.length === 1) {
            switch (color.posArr[0]) {
              case 0:
                if (tempIndex === 1 || tempIndex === 2) ret = arrIndex;
                break;
              case 1:
                if (tempIndex === 3) ret = arrIndex;
                break;
              case 2:
                if (tempIndex === 3) ret = arrIndex;
                break;
            }
          }
        }
      });

      if (ret != -1) {
        arr[ret].posArr.push(tempIndex);
        arr[ret].posArr.sort((a, b) => a - b);
      } else arr.push(new GameColor(`${id}`, ...[tempIndex]));
    });
    item.setData(arr);
  }

  onTouchStart(t: EventTouch) {
    if (!this.releaseEnable) return;
    const uiPos = new Vec3(t.getUILocation().x, t.getUILocation().y);
    const localPos = this.node.getComponent(UITransform).convertToNodeSpaceAR(uiPos);
    const index = this.getTouchCol(localPos.x);
    this.lastIndex = index;
    // this.curSingleItem.node.setPosition((-(this.col - 1) / 2) * GameModel.Ins().itemSize.width + index * GameModel.Ins().itemSize.width, this.bornPos.getPosition().y);
    // 预处理结果
    this.showItemLight(index);
  }

  onTouchMove(t: EventTouch) {
    if (!this.releaseEnable) return;
    const uiPos = new Vec3(t.getUILocation().x, t.getUILocation().y);
    const localPos = this.node.getComponent(UITransform).convertToNodeSpaceAR(uiPos);
    const index = this.getTouchCol(localPos.x);
    // this.curSingleItem.node.setPosition((-(this.col - 1) / 2) * GameModel.Ins().itemSize.width + index * GameModel.Ins().itemSize.width, this.bornPos.getPosition().y);
    if (this.lastIndex != index) {
      // 预处理结果
      this.showItemLight(index);
    }
    this.lastIndex = index;
  }

  onTouchEnd(t: EventTouch) {
    if (!this.releaseEnable) return;
    const uiPos = new Vec3(t.getUILocation().x, t.getUILocation().y);
    const localPos = this.node.getComponent(UITransform).convertToNodeSpaceAR(uiPos);
    const index = this.getTouchCol(localPos.x);
    // this.curSingleItem.node.setPosition((-(this.col - 1) / 2) * GameModel.Ins().itemSize.width + index * GameModel.Ins().itemSize.width, this.bornPos.getPosition().y);
    this.lastIndex = index;
    this.showItemLight(-1);
    if (GameData.get(GameParams.gameLevel) <= 2) {
      if (this.guideStep >= this.guideIndexArr.length || this.lastIndex == this.guideIndexArr[this.guideStep] - 1) {
        this.showGuide(false);
        this.releaseSingleItem();
      }
    } else {
      this.releaseSingleItem();
    }
  }

  showGuide(isShow: boolean) {
    if (isShow && this.guideStep < this.guideIndexArr.length) {
      if (this.guideItem === null) {
        this.guideItem = this.poolFac.pop('guide', 'maingame/effects', 'guide');
        GameModel.Ins().orderMac.coinParent.addChild(this.guideItem);
      }
      const pos = new Vec3((-(this.col - 1) / 2) * GameModel.Ins().itemSize.width + (this.guideIndexArr[this.guideStep] - 1) * GameModel.Ins().itemSize.width, 0);
      this.guideItem.setPosition(pos);
      this.guideItem.active = true;
    } else {
      this.guideStep++;
      if (this.guideItem) this.guideItem.active = false;
    }
  }

  showItemLight(index: number) {
    // console.log('show light', index);
    for (let j = 0; j < this.col; j++) {
      for (let i = 0; i < this.row; i++) {
        const item = this.getGridItem(j, i);
        if (item.isBox || item.isCrack || item.isDisable) continue;
        item.showLight(index === j);
      }
    }

    Tween.stopAllByTarget(this.curSingleItem.node);
    if (index < 0) return;
    const endPos = new Vec3((-(this.col - 1) / 2) * GameModel.Ins().itemSize.width + index * GameModel.Ins().itemSize.width, this.bornPos.getPosition().y);
    tween(this.curSingleItem.node).to(0.2, { position: endPos }, { easing: 'backOut' }).start();
  }

  /** 释放当前对象 */
  releaseSingleItem() {
    AudioManager.Singleton.playSound(SoundCode.JELLY_SLIP);

    const bottomItem = this.getGridItem(this.lastIndex, this.row - 1);
    const topItem = this.getTopEmpty(bottomItem);
    if (!topItem.isEmpty) return;
    topItem.resetDestory();
    this.releaseEnable = false;
    this.combeCount = 0;
    const endPos = topItem.node.getPosition().clone();

    Tween.stopAllByTarget(this.curSingleItem.node);
    this.curSingleItem.node.setPosition((-(this.col - 1) / 2) * GameModel.Ins().itemSize.width + this.lastIndex * GameModel.Ins().itemSize.width, this.bornPos.getPosition().y);
    const func = () => {
      this.curSingleItem.node.active = false;
      topItem.setData(this.curSingleItem.colorData);
      topItem.refrechColor();
      this.checkProp(topItem);
      // this.curTime = Date.now();
    };
    tween(this.curSingleItem.node).to(this.shootSpeed, { position: endPos }).call(func.bind(this)).start();
  }

  // 检测当前道具
  checkProp(item: GridItem, revive: boolean = false) {
    if (revive || ['item_scoop1', `item_scoop2`].indexOf(item.colorData[0].colorId) != -1) {
      const items: GridItem[] = [];
      if (revive) {
        items.push(...this.getRowItem(this.getGridItem(2, 4)));
      } else {
        switch (item.colorData[0].colorId) {
          case 'item_scoop1':
            this.prop1Enable = true;
            // items.push(...this.getRowItem(item));
            return this.propCheck(item.colorData[0].colorId, this.getRowItem(item), item.node.getPosition().clone());
          case 'item_scoop2':
            this.prop1Enable = true;
            // items.push(...this.getColItem(item));
            return this.propCheck(item.colorData[0].colorId, this.getColItem(item), item.node.getPosition().clone());
        }
      }
      if (items.length <= 0) {
        this.checkMachine();
      } else {
        while (items.length) {
          const element = items.shift();
          element.colorItem.forEach((color) => {
            color.destroyFlag = true;
          });
        }
        this.checkMachine();
      }
    } else {
      const items: GridItem[] = [];
      const posTop: Vec3[] = [];
      /** 撞击位移像素 */
      const moveSpace = 5;
      posTop.push(v3(0, moveSpace, 0));
      posTop.push(v3(0, -moveSpace, 0));

      items.push(...this.getColItem(item));
      items.forEach((element, i) => {
        element.colorItem.forEach((color, j) => {
          const beginPos = color.node.getPosition();
          const centerPos = beginPos.clone();
          const endPos = beginPos.clone();
          if (Tool.judge(50)) {
            centerPos.x += posTop[1].x;
            centerPos.y += posTop[1].y;
            endPos.x += posTop[0].x;
            endPos.y += posTop[0].y;
          } else {
            centerPos.x += posTop[0].x;
            centerPos.y += posTop[0].y;
            endPos.x += posTop[1].x;
            endPos.y += posTop[1].y;
          }
          Tween.stopAllByTarget(color.node);
          tween(color.node)
            .to(0.08, { position: centerPos })
            .to(0.08, { position: endPos })
            .to(0.08, { position: beginPos })
            .call(i === items.length - 1 && j === element.colorItem.length - 1 ? this.checkMachine.bind(this) : null)
            .start();
        });
      });
    }
  }

  propCheck(prop: string, items: GridItem[], beginPos?: Vec3) {
    this.releaseEnable = false;
    const tweenArr: GridItem[][] = [];
    switch (prop) {
      case 'item_scoop1' /** 由内而外消除 */:
        items.forEach((item) => {
          item.colorItem.forEach((color) => {
            color.destroyFlag = true;
          });

          let ret = -1;
          tweenArr.forEach((arr, index) => {
            arr.forEach((temp) => {
              if (Math.abs(temp.col + 1 - (this.col + 1) / 2) === Math.abs(item.col + 1 - (this.col + 1) / 2)) {
                ret = index;
              }
            });
          });
          if (ret >= 0) tweenArr[ret].push(item);
          else tweenArr.push([item]);
        });
        tweenArr.sort((a, b) => Math.abs(a[0].col + 1 - (this.col + 1) / 2) - Math.abs(b[0].col + 1 - (this.col + 1) / 2));
        break;
      case 'item_box':
      case 'item_scoop2' /** 由下到上消除 */:
        items.forEach((item) => {
          tweenArr.push([item]);
        });
        tweenArr.sort((a, b) => b[0].row - a[0].row);
        break;
    }
    const tempColor: ColorItem[][] = [];
    tweenArr.forEach((itemArr) => {
      const arr = [];
      itemArr.forEach((item) => {
        arr.push(...item.colorItem.splice(0));
        item.setData([new GameColor(`-1`, 0, 1, 2, 3)]);
      });
      tempColor.push(arr);
    });

    tempColor.forEach((arr, i) => {
      arr.forEach((color, j) => {
        Tween.stopAllByTarget(color.node);
        tween(color.node)
          .delay(i * 0.2)
          .call(this.afterTween.bind(this, color, i, j, tempColor))
          .start();
      });
    });
    const itemSize = GameModel.Ins().itemSize;
    switch (prop) {
      case 'item_scoop1':
        {
          const effectItemRight = this.poolFac.pop('ItemArrow', 'maingame/effects', 'ItemArrow');
          const effectItemLeft = this.poolFac.pop('ItemArrow', 'maingame/effects', 'ItemArrow');
          try {
            effectItemRight.getComponentInChildren(ParticleSystem2D).resetSystem();
            effectItemLeft.getComponentInChildren(ParticleSystem2D).resetSystem();
          } catch {
            console.log('粒子未正常播放');
          }

          effectItemRight.getChildByName('arrow').angle = 0;
          effectItemLeft.getChildByName('arrow').angle = 180;

          GameModel.Ins()
            .loadDynamicRes<SpriteFrame>('public/sprite/common/main_ui_hengdao2/spriteFreme')
            .then((spr) => {
              effectItemRight.getChildByName('arrow').getComponent(Sprite).spriteFrame = spr;
            });
          GameModel.Ins()
            .loadDynamicRes<SpriteFrame>('public/sprite/common/main_ui_hengdao1/spriteFreme')
            .then((spr) => {
              effectItemLeft.getChildByName('arrow').getComponent(Sprite).spriteFrame = spr;
            });

          // Tool.getSpriteByKey('', 'public/sprite/common/main_ui_hengdao2').then((spr) => {
          //   effectItemRight.getChildByName('arrow').getComponent(Sprite).spriteFrame = spr;
          // });
          // Tool.getSpriteByKey('', 'public/sprite/common/main_ui_hengdao1').then((spr) => {
          //   effectItemLeft.getChildByName('arrow').getComponent(Sprite).spriteFrame = spr;
          // });
          this.flyParent.addChild(effectItemRight);
          this.flyParent.addChild(effectItemLeft);
          Tween.stopAllByTarget(effectItemRight);
          Tween.stopAllByTarget(effectItemLeft);
          effectItemRight.setPosition(beginPos);
          effectItemLeft.setPosition(beginPos);
          const endPosRight = new Vec3(-((this.col - 1) / 2) * itemSize.width + this.col * itemSize.width, beginPos.y);
          const endPosLeft = new Vec3(-((this.col - 1) / 2) * itemSize.width + -1 * itemSize.width, beginPos.y);
          tween(effectItemRight)
            .to(this.cleanSpeed, { position: endPosRight })
            .call(() => this.poolFac.push(effectItemRight))
            .start();
          tween(effectItemLeft)
            .to(this.cleanSpeed, { position: endPosLeft })
            .call(() => this.poolFac.push(effectItemLeft))
            .start();
        }
        break;
      case 'item_scoop2':
        {
          const effectItem = this.poolFac.pop('ItemArrow', 'maingame/effects', 'ItemArrow');
          try {
            effectItem.getComponentInChildren(ParticleSystem2D).resetSystem();
          } catch {
            console.log('粒子未正常播放');
          }
          effectItem.getChildByName('arrow').angle = 90;
          GameModel.Ins()
            .loadDynamicRes<SpriteFrame>('public/sprite/common/main_ui_shudao/spriteFreme')
            .then((spr) => {
              effectItem.getChildByName('arrow').getComponent(Sprite).spriteFrame = spr;
            });
          // Tool.getSpriteByKey('', 'public/sprite/common/main_ui_shudao').then((spr) => {
          //   effectItem.getChildByName('arrow').getComponent(Sprite).spriteFrame = spr;
          // });
          this.flyParent.addChild(effectItem);
          Tween.stopAllByTarget(effectItem);
          effectItem.setPosition(beginPos);
          const endPos = new Vec3(beginPos.x, ((this.row - 1) / 2) * itemSize.width - -1 * itemSize.width + 13 / 2);
          tween(effectItem)
            .to(this.cleanSpeed, { position: endPos })
            .call(() => this.poolFac.push(effectItem))
            .start();
        }
        break;
    }
  }

  /** 获取触点对应列下标 */
  getTouchCol(x: number) {
    const itemSize = GameModel.Ins().itemSize;
    let index = Math.floor((x - (-this.col / 2) * itemSize.width) / itemSize.width);
    index = index <= 0 ? 0 : index >= this.col - 1 ? this.col - 1 : index;
    return index;
  }

  /** 检测没有空格子了 */
  checkNotEmpty() {
    let ret = true;
    this.gridItems.forEach((item) => {
      if (item.isEmpty) ret = false;
    });
    return ret;
  }

  /** 执行机器检测 */
  checkMachine() {
    // LogUtil.i('CellMachine', 'checkMachine--->>>', (Date.now() - this.curTime) / 1000 + 's');
    // this.curTime = Date.now();
    this.releaseEnable = false;
    this.removeArr = [];
    if (this.checkRemove()) {
      setTimeout(this.actionTween.bind(this), this.checkSpace * 1000);
    } else {
      this.actionComplate();
    }
  }

  /** 检测消除 */
  checkRemove() {
    // LogUtil.i('CellMachine', 'checkRemove', (Date.now() - this.curTime) / 1000 + 's');
    // this.curTime = Date.now();
    for (let i = 0; i < this.gridItems.length; i++) {
      const item = this.gridItems[i];
      if (item.isCrack || item.isEmpty || item.isBox || item.isDisable) continue;
      this.checkSelf(item);
      this.checkRightItem(item);
      this.checkDownItem(item);
    }
    let ret = false;
    for (let i = 0; i < this.gridItems.length; i++) {
      const item = this.gridItems[i];
      item.colorItem.forEach((color) => {
        if (color.destroyFlag) ret = true;
      });
    }
    return ret;
  }

  /** 执行消除动画 */
  actionTween() {
    // LogUtil.i('CellMachine', 'actionTween--->>>', (Date.now() - this.curTime) / 1000 + 's');
    // this.curTime = Date.now();
    while (this.flyPos.length) this.flyPos.pop();
    this.flyPos = [];
    for (let i = 0; i < this.gridItems.length; i++) {
      const item = this.gridItems[i];
      item.colorItem.forEach((color, index) => {
        if (color.destroyFlag) {
          this.addCanHitBox(item, item.colorData[index].posArr);
        }
      });
    }

    while (this.canBoxArr.length) this.canBoxArr.pop().colorItem[0].destroyFlag = true;
    while (this.removeArr.length) this.removeArr.pop();
    this.removeArr = [];
    let ret = false;
    for (let i = 0; i < this.gridItems.length; i++) {
      const item = this.gridItems[i];
      if (item.isEmpty || item.isCrack || item.isDisable) continue;
      const retArr = item.tryRemoveColor();
      if (retArr.length > 0) {
        ret = true;
      }
    }

    if (ret) {
      const coinParentUI = GameModel.Ins().orderMac.coinParent.getComponent(UITransform);

      this.removeArr.forEach((arr, i) => {
        if (arr.length < 2) {
          Tween.stopAllByTarget(arr[0].node);
          tween(arr[0].node)
            .delay(this.cleanSpeed)
            .call(this.afterTween.bind(this, arr[0], i, 0, i === this.removeArr.length - 1 ? this.removeArr : []))
            .start();
        } else if (this.propItem) {
          arr.forEach((colorItem, j) => {
            Tween.stopAllByTarget(colorItem.node);
            tween(colorItem.node)
              .delay(this.checkSpace * 0.1)
              .call(this.afterTween.bind(this, colorItem, i, j, i === this.removeArr.length - 1 && j === arr.length - 1 ? this.removeArr : []))
              .start();
          });
        } else
          arr.forEach((colorItem, j) => {
            if (j > 0) {
              /** 上一个对象 */
              const lastItem = arr[j - 1];
              /** 当前对象 */
              const curItem = arr[j];
              /** 计算方向 */
              const lastPos = coinParentUI.convertToNodeSpaceAR(lastItem.node.getWorldPosition());
              const curPos = coinParentUI.convertToNodeSpaceAR(curItem.node.getWorldPosition());
              const lastDir = Tool.Vec2Sub(new Vec2(lastPos.x, lastPos.y), new Vec2(curPos.x, curPos.y)).normalize();
              const curDir = Tool.Vec2Mut(lastDir, -1).normalize();
              /** 原点 */
              const lastBeginPos = lastItem.node.getPosition().clone();
              const curBeginPos = curItem.node.getPosition().clone();
              /** 目标点 */
              const lastMovePos = lastBeginPos.clone();
              const curMovePos = curBeginPos.clone();
              lastMovePos.x += lastDir.x * 25;
              lastMovePos.y += lastDir.y * 25;
              curMovePos.x += curDir.x * 25;
              curMovePos.y += curDir.y * 25;
              /** 执行动画 */
              Tween.stopAllByTarget(lastItem.node);
              Tween.stopAllByTarget(curItem.node);
              tween(lastItem.node)
                .to(this.cleanSpeed * 0.6, { position: lastMovePos }, { easing: 'backIn' })
                .to(this.cleanSpeed * 0.4, { position: lastBeginPos }, { easing: 'quadOut' })
                .call(this.afterTween.bind(this, lastItem, -1, -1, []))
                .start();
              tween(curItem.node)
                .to(this.cleanSpeed * 0.6, { position: curMovePos }, { easing: 'backIn' })
                .to(this.cleanSpeed * 0.4, { position: curBeginPos }, { easing: 'quadOut' })
                .call(this.afterTween.bind(this, curItem, i, j, i === this.removeArr.length - 1 && j === arr.length - 1 ? this.removeArr : []))
                .start();
            }
          });
      });
    } else {
      // 直接走下一步
      setTimeout(this.tweenComplate.bind(this, ret), this.cleanSpeed * 1000);
    }
  }

  afterTween(item: ColorItem, i: number, j: number, arr) {
    console.log(i, j, arr.length);

    switch (item.curColor) {
      case '':
        break;
      case 'obstacle_box':
        this.playEffect('broken', item.node.getWorldPosition().clone());
        break;
      default:
        GameModel.Ins().addReduceData(item.curColor, 1);
        GameModel.Ins().cellMachine.flyPos.push({ color: item.curColor, wPos: item.node.getWorldPosition().clone() });
        GameModel.Ins().cellMachine.playEffect('splash', item.node.getWorldPosition().clone(), item.curColor);
        GameModel.Ins().addGameMoney(DataMgr.tables.TbColor.get(item.curColor).value, item.node.getWorldPosition().clone());
        break;
    }
    Tween.stopAllByTarget(item.node);
    item.reset();
    GameModel.Ins().cellMachine.poolFac.push(item.node);
    if (i >= 0 && j >= 0 && arr.length > 0 && i === arr.length - 1 && j === arr[i].length - 1) this.tweenComplate(true);
  }

  /** 动画结束 */
  tweenComplate(ret: boolean) {
    // LogUtil.i('CellMachine', 'tweenComplate--->>>', (Date.now() - this.curTime) / 1000 + 's');
    // this.curTime = Date.now();

    const canRemove = this.checkRemove();
    if (canRemove) {
      if (ret) {
        this.addCombe();
        AudioManager.Singleton.playSound(SoundCode.JELLY_MATCH);
        MultiPlatform.Ins().platformUnit.openVibrateShort();
        GameModel.Ins().orderMac.reduceVisitorColor(GameModel.Ins().reduceColorArr);
        // GameModel.Ins().orderMac.refreshVisitorOrder();
      }
      setTimeout(this.actionTween.bind(this), this.shapeChange * 1100);
    } else {
      if (ret) {
        this.addCombe();
        AudioManager.Singleton.playSound(SoundCode.JELLY_MATCH);
        MultiPlatform.Ins().platformUnit.openVibrateShort();
        GameModel.Ins().orderMac.reduceVisitorColor(GameModel.Ins().reduceColorArr);
        // GameModel.Ins().orderMac.refreshVisitorOrder();
        setTimeout(this.actionMove.bind(this), this.shapeChange * 1100);
      } else {
        setTimeout(this.actionComplate.bind(this), this.shapeChange * 1100);
      }
    }
  }

  /** 检测是否可移动 */
  checkMove() {
    for (let i = 0; i < this.gridItems.length; i++) {
      const item = this.gridItems[i];
      if (item.isEmpty || item.isCrack || item.isDisable) continue;
      const topItem = this.getTopEmpty(item);
      if (item === topItem) continue;
      return true;
    }
    return false;
  }

  /** 执行移动 */
  actionMove() {
    if (!this.checkMove()) return this.actionComplate();

    // LogUtil.i('CellMachine', 'actionMove--->>>', (Date.now() - this.curTime) / 1000 + 's');
    // this.curTime = Date.now();
    this.colArr = [];
    let move = 0;
    for (let i = 0; i < this.gridItems.length; i++) {
      const item = this.gridItems[i];
      if (item.isEmpty || item.isCrack || item.isDisable) continue;
      const topItem = this.getTopEmpty(item);
      if (item === topItem) continue;
      move = i;
      if (this.colArr.indexOf(item.col) === -1) this.colArr.push(item.col);
      const retData = [...item.colorData];
      topItem.setData(retData);
      item.setData([new GameColor('-1', ...[0, 1, 2, 3])]);

      Tween.stopAllByTarget(item.colorParent);
      let endPos = topItem.node.getWorldPosition().clone();
      endPos = item.node.getComponent(UITransform).convertToNodeSpaceAR(endPos);
      const func0 = () => {
        topItem.refrechColor();
        item.refrechColor();
        item.colorParent.setPosition(0, 0);
        // eslint-disable-next-line @typescript-eslint/no-unused-expressions
        move > 0 && i === move && this.moveComplate();
      };
      tween(item.colorParent).to(this.moveSpeed, { position: endPos }).call(func0.bind(this)).start();
    }
    if (move <= 0) this.actionComplate();
  }

  /** 移动回调 */
  moveComplate() {
    let colCount = 0;
    this.colArr.forEach((col, k) => {
      const item = this.getGridItem(col, 0);
      const items: GridItem[] = [];
      const posTop: Vec3[] = [];
      /** 撞击位移像素 */
      const moveSpace = 5;
      posTop.push(v3(0, moveSpace, 0));
      posTop.push(v3(0, -moveSpace, 0));

      items.push(...this.getColItem(item));
      if (items.length > 0) colCount++;
      items.forEach((element, i) => {
        element.colorItem.forEach((color, j) => {
          const beginPos = color.node.getPosition();
          const centerPos = beginPos.clone();
          const endPos = beginPos.clone();
          if (Tool.judge(50)) {
            centerPos.x += posTop[1].x;
            centerPos.y += posTop[1].y;
            endPos.x += posTop[0].x;
            endPos.y += posTop[0].y;
          } else {
            centerPos.x += posTop[0].x;
            centerPos.y += posTop[0].y;
            endPos.x += posTop[1].x;
            endPos.y += posTop[1].y;
          }
          Tween.stopAllByTarget(color.node);
          tween(color.node)
            .to(0.08, { position: centerPos })
            .to(0.08, { position: endPos })
            .to(0.08, { position: beginPos })
            .call(k === colCount - 1 && i === items.length - 1 && j === element.colorItem.length - 1 ? this.actionComplate.bind(this) : null)
            .start();
        });
      });
    });
    if (this.colArr.length <= 0) this.actionComplate();
  }

  actionComplate() {
    // LogUtil.i('CellMachine', 'actionComplate--->>>', (Date.now() - this.curTime) / 1000 + 's');
    // this.curTime = Date.now();
    if (this.checkRemove()) return setTimeout(this.actionTween.bind(this), this.checkSpace * 1000);
    else if (this.checkMove()) return setTimeout(this.actionMove.bind(this), this.shapeChange * 1100);
    else if (GameModel.Ins().readySettlement) return GameModel.Ins().settlementGame(true);
    else if (this.checkNotEmpty()) GameModel.Ins().settlementGame();
    else this.createSingleItem();
    this.showCombeTip();
    this.combeCount = -1;
    this.combeTxt = '';
  }

  /** 检测能消除的箱子 */
  addCanHitBox(item: GridItem, posArr: number[]) {
    const tempArr = [...posArr];
    const topItem = tempArr.indexOf(0) !== -1 || tempArr.indexOf(1) !== -1 ? this.getGridItem(item.col, item.row - 1) : null;
    const rightItem = tempArr.indexOf(1) !== -1 || tempArr.indexOf(3) !== -1 ? this.getGridItem(item.col + 1, item.row) : null;
    const downItem = tempArr.indexOf(2) !== -1 || tempArr.indexOf(3) !== -1 ? this.getGridItem(item.col, item.row + 1) : null;
    const leftItem = tempArr.indexOf(0) !== -1 || tempArr.indexOf(2) !== -1 ? this.getGridItem(item.col - 1, item.row) : null;
    if (topItem && topItem.isBox && this.canBoxArr.indexOf(topItem) === -1) this.canBoxArr.push(topItem);
    if (rightItem && rightItem.isBox && this.canBoxArr.indexOf(rightItem) === -1) this.canBoxArr.push(rightItem);
    if (downItem && downItem.isBox && this.canBoxArr.indexOf(downItem) === -1) this.canBoxArr.push(downItem);
    if (leftItem && leftItem.isBox && this.canBoxArr.indexOf(leftItem) === -1) this.canBoxArr.push(leftItem);
  }

  /** 获取该列最顶上为空的格子 */
  getTopEmpty(item: GridItem): GridItem {
    const topItem = this.getGridItem(item.col, item.row - 1);
    if (topItem === null || topItem.colorData[0].colorId !== '-1') return item;
    return this.getTopEmpty(topItem);
  }

  /** 添加本次消除的颜色对象 */
  addRemoveColorItem(item: ColorItem) {
    let index = -1;
    this.removeArr.forEach((arr, i) => {
      if (arr.indexOf(item) != -1) index = i;
    });

    if (index != -1) return;
    else {
      let closeIndex = -1;
      this.removeArr.forEach((arr, i) => {
        arr.forEach((color) => {
          if (
            color.curColor === item.curColor &&
            ((color.parentCol === item.parentCol && Math.abs(color.parentRow - item.parentRow) <= 1) || (color.parentRow === item.parentRow && Math.abs(color.parentCol - item.parentCol) <= 1))
          ) {
            closeIndex = i;
          }
        });
      });
      if (closeIndex !== -1) this.removeArr[closeIndex].push(item);
      else this.removeArr.push([item]);
    }

    for (let i = 0; i < this.removeArr.length; i++) {
      if (this.removeArr[i].length === 1) {
        const tempItem = this.removeArr[i][0];
        if (tempItem.curColor === 'obstacle_box') continue;
        for (let j = 0; j < this.removeArr.length; j++) {
          if (i != j && this.removeArr[j].length >= 2) {
            let ret = false;
            this.removeArr[j].forEach((color) => {
              if (
                color.curColor === tempItem.curColor &&
                ((color.parentCol === tempItem.parentCol && Math.abs(color.parentRow - tempItem.parentRow) <= 1) ||
                  (color.parentRow === tempItem.parentRow && Math.abs(color.parentCol - tempItem.parentCol) <= 1))
              ) {
                ret = true;
              }
            });

            if (ret) {
              this.removeArr[j].push(tempItem);
              this.removeArr.splice(i, 1);
              break;
            }
          }
        }
      }
    }
  }

  checkSelf(item: GridItem) {
    for (let i = 0; i < 3; i++) {
      switch (i) {
        case 0:
          if (item.getColor(0) === item.getColor(1) && item.getColorIndex(0) != item.getColorIndex(1)) {
            item.colorItem[item.getColorIndex(0)].destroyFlag = true;
            item.colorItem[item.getColorIndex(1)].destroyFlag = true;
          }
          if (item.getColor(0) === item.getColor(2) && item.getColorIndex(0) != item.getColorIndex(2)) {
            item.colorItem[item.getColorIndex(0)].destroyFlag = true;
            item.colorItem[item.getColorIndex(2)].destroyFlag = true;
          }
          break;
        case 1:
          if (item.getColor(1) === item.getColor(3) && item.getColorIndex(1) != item.getColorIndex(3)) {
            item.colorItem[item.getColorIndex(1)].destroyFlag = true;
            item.colorItem[item.getColorIndex(3)].destroyFlag = true;
          }
          break;
        case 2:
          if (item.getColor(2) === item.getColor(3) && item.getColorIndex(2) != item.getColorIndex(3)) {
            item.colorItem[item.getColorIndex(2)].destroyFlag = true;
            item.colorItem[item.getColorIndex(3)].destroyFlag = true;
          }
          break;
      }
    }
  }

  checkUpItem(item: GridItem) {
    const tempItem = this.getGridItem(item.col, item.row - 1);
    if (tempItem === null) return;

    // 检测 0,1 -> 2,3是否有对应颜色
    if (item.getColor(0) != '-1' && tempItem.getColor(2) != '-1' && item.getColor(0) === tempItem.getColor(2)) {
      item.colorItem[item.getColorIndex(0)].destroyFlag = true;
      tempItem.colorItem[tempItem.getColorIndex(2)].destroyFlag = true;
    }
    if (item.getColor(1) != '-1' && tempItem.getColor(3) != '-1' && item.getColor(1) === tempItem.getColor(3)) {
      item.colorItem[item.getColorIndex(1)].destroyFlag = true;
      tempItem.colorItem[tempItem.getColorIndex(3)].destroyFlag = true;
    }
  }

  checkRightItem(item: GridItem) {
    const rightItem = this.getGridItem(item.col + 1, item.row);
    if (rightItem === null) return;

    // 检测 1,3 -> 0,2是否有对应颜色
    if (item.getColor(1) != '-1' && rightItem.getColor(0) != '-1' && item.getColor(1) === rightItem.getColor(0)) {
      // if (!item.colorItem[item.getColorIndex(1)].destroyFlag && !rightItem.colorItem[rightItem.getColorIndex(0)].destroyFlag) this.addCombe();
      item.colorItem[item.getColorIndex(1)].destroyFlag = true;
      rightItem.colorItem[rightItem.getColorIndex(0)].destroyFlag = true;
    }

    if (item.getColor(3) != '-1' && rightItem.getColor(2) != '-1' && item.getColor(3) === rightItem.getColor(2)) {
      // if (!item.colorItem[item.getColorIndex(3)].destroyFlag && !rightItem.colorItem[rightItem.getColorIndex(2)].destroyFlag) this.addCombe();
      item.colorItem[item.getColorIndex(3)].destroyFlag = true;
      rightItem.colorItem[rightItem.getColorIndex(2)].destroyFlag = true;
    }
  }

  checkDownItem(item: GridItem) {
    const downItem = this.getGridItem(item.col, item.row + 1);
    if (downItem === null || downItem.colorItem.length <= 0) return;
    // 检测 2,3 -> 0,1是否有对应颜色
    if (item.getColor(2) != '-1' && downItem.getColor(0) != '-1' && item.getColor(2) === downItem.getColor(0)) {
      // if (!item.colorItem[item.getColorIndex(2)].destroyFlag && !downItem.colorItem[downItem.getColorIndex(0)].destroyFlag) this.addCombe();
      item.colorItem[item.getColorIndex(2)].destroyFlag = true;
      downItem.colorItem[downItem.getColorIndex(0)].destroyFlag = true;
    }
    if (item.getColor(3) != '-1' && downItem.getColor(1) != '-1' && item.getColor(3) === downItem.getColor(1)) {
      // if (!item.colorItem[item.getColorIndex(3)].destroyFlag && !downItem.colorItem[downItem.getColorIndex(1)].destroyFlag) this.addCombe();
      item.colorItem[item.getColorIndex(3)].destroyFlag = true;
      downItem.colorItem[downItem.getColorIndex(1)].destroyFlag = true;
    }
  }

  checkLeftItem(item: GridItem) {
    const tempItem = this.getGridItem(item.col - 1, item.row);
    if (tempItem === null) return;

    // 检测 0,2 -> 1,3是否有对应颜色
    if (item.getColor(0) != '-1' && tempItem.getColor(1) != '-1' && item.getColor(0) === tempItem.getColor(1)) {
      item.colorItem[item.getColorIndex(0)].destroyFlag = true;
      tempItem.colorItem[tempItem.getColorIndex(1)].destroyFlag = true;
    }
    if (item.getColor(2) != '-1' && tempItem.getColor(3) != '-1' && item.getColor(2) === tempItem.getColor(3)) {
      item.colorItem[item.getColorIndex(2)].destroyFlag = true;
      tempItem.colorItem[tempItem.getColorIndex(3)].destroyFlag = true;
    }
  }

  /** 增加连击 */
  addCombe() {
    if (this.combeCount != -1) this.combeCount++;
    // let str = '';
    switch (this.combeCount) {
      case -1:
      case 0:
      case 1:
      case 2 /** good */:
        this.combeTxt = 'Good';
        break;
      case 3 /** great */:
        this.combeTxt = 'Great';
        break;
      case 4 /** amazing */:
        this.combeTxt = 'Amazing';
        break;
      case 5 /** unbelievable */:
      default:
        this.combeTxt = 'Unbelievable';
        break;
      // case 6: /** unbelievable */
      //   break;
    }
    // return str;
    // if (str === '') return;
    // const tips = this.poolFac.pop('combeTips', 'maingame/tips', 'combeTips');
    // const lab = tips.getComponentInChildren(Label);
    // lab.string = `${str}`;
    // GameModel.Ins().orderMac.coinParent.addChild(tips);
    // Tween.stopAllByTarget(tips);
    // const func = () => {
    //   this.poolFac.push(tips);
    // };
    // tween(tips).delay(1).call(func.bind(this)).start();
  }

  showCombeTip() {
    if (this.combeTxt === '') return;
    const tips = this.poolFac.pop('combeTips', 'maingame/tips', 'combeTips');
    const lab = tips.getComponentInChildren(Label);
    lab.string = `${this.combeTxt}`;
    switch (this.combeTxt) {
      case 'Good':
        AudioManager.Singleton.playSound(SoundCode.VOICE_GOOD);
        break;
      case 'Great':
        AudioManager.Singleton.playSound(SoundCode.VOICE_GREAT);
        break;
      case 'Amazing':
        AudioManager.Singleton.playSound(SoundCode.VOICE_AMAZING);
        break;
      case 'Unbelievable':
        AudioManager.Singleton.playSound(SoundCode.VOICE_UNBELIEVABLE);
        break;
    }

    GameModel.Ins().orderMac.coinParent.addChild(tips);
    Tween.stopAllByTarget(tips);
    const func = () => {
      this.poolFac.push(tips);
    };
    tween(tips).delay(1).call(func.bind(this)).start();
  }

  getColItem(item: GridItem) {
    const items: GridItem[] = [];
    for (let i = 0; i < this.row; i++) {
      const tempItem = this.getGridItem(item.col, i);
      if (tempItem.isEmpty || tempItem.isCrack || tempItem.isDisable) continue;
      // tempItem.colorItem.forEach((element) => {
      //   element.destroyFlag = true;
      // });
      items.push(tempItem);
    }
    return items;
  }

  getRowItem(item: GridItem) {
    const items: GridItem[] = [];
    for (let i = 0; i < this.col; i++) {
      const tempItem = this.getGridItem(i, item.row);
      if (tempItem.isEmpty || tempItem.isCrack || tempItem.isDisable) continue;
      // tempItem.colorItem.forEach((element) => {
      //   element.destroyFlag = true;
      // });
      items.push(tempItem);
    }
    return items;
  }

  /** 获取对应位置的单元格 */
  getGridItem(col: number, row: number) {
    if (col < 0 || row < 0 || col >= this.col || row >= this.row) return null;
    return this.gridItems[col * this.col + row];
  }

  /** 创建飞行动画 */
  createFlyColor(color: string, eWorldPos: Vec3) {
    let bWorldPos = null;
    for (let i = 0; i < this.flyPos.length; i++) {
      if (this.flyPos[i].color === color) {
        bWorldPos = this.flyPos[i].wPos;
        this.flyPos.splice(i, 1).shift();
        break;
      }
    }
    if (bWorldPos === null) return;
    const item = this.poolFac.pop(PoolElementType.COLOR_ITEM, 'maingame/game', PoolElementType.COLOR_ITEM);
    const trid = this.poolFac.pop('tuowei', 'maingame/effects', 'tuowei');
    const script = item.getComponent(ColorItem);
    script.setColor(color, -1, -1);
    script.Width = 112 / 2;
    script.Height = 125 / 2;
    script.icon.node.setScale(0.5, 0.5);
    this.flyParent.addChild(trid);
    this.flyParent.addChild(item);
    const beginPos = this.flyParent.getComponent(UITransform).convertToNodeSpaceAR(bWorldPos);
    const endPos = this.flyParent.getComponent(UITransform).convertToNodeSpaceAR(eWorldPos);
    // 播放特效 |
    Tween.stopAllByTarget(item);
    Tween.stopAllByTarget(trid);
    item.setScale(0, 0);
    item.setPosition(beginPos); //
    trid.setPosition(beginPos);
    const func0 = () => {
      Tween.stopAllByTarget(item);
      this.poolFac.push(item);
    };
    const func1 = () => {
      Tween.stopAllByTarget(trid);
      this.poolFac.push(trid);
    };

    tween(item)
      .to(0.1, { scale: v3(1, 1, 1) }, { easing: 'backOut' })
      .to(0.4, { position: endPos })
      .call(func0.bind(this))
      .start();
    tween(trid).delay(0.1).to(0.4, { position: endPos }).call(func1.bind(this)).start();
  }

  /** 播放特效 */
  playEffect(key: string, pos: Vec3, data?) {
    let item: Node = null;
    const retPos: Vec3 = this.ectParent.getComponent(UITransform).convertToNodeSpaceAR(pos);
    switch (key) {
      case 'splash':
        item = this.poolFac.pop('splash', 'maingame/effects', 'splash');
        if (item) {
          const spr = item.getComponent(Sprite);
          let color = '';
          switch (data) {
            case 'blue':
              color = '#5cb0ed';
              break;
            case 'purple':
              color = '#e557ff';
              break;
            case 'pink':
              color = '#ff6bd3';
              break;
            case 'red':
              color = '#ff7e84';
              break;
            case 'yellow':
              color = '#ffe16d';
              break;
            case 'orange':
              color = '#ffa954';
              break;
            case 'cyan':
              color = '#6ce8fe';
              break;
            case 'green':
              color = '#b7e956';
              break;
            case 'green_dark':
              color = '#48d173';
              break;
            case 'brown':
              color = '#b46868';
              break;
          }
          spr.color = new Color().fromHEX(color);
        }
        break;
      case 'broken':
        item = this.poolFac.pop('broken', 'maingame/effects', 'broken');
        AudioManager.Singleton.playSound(SoundCode.BOX_BROKEN);
        break;
      case 'box':
        item = this.poolFac.pop('box', 'maingame/effects', 'box');
        retPos.y -= 10;
        break;
    }
    if (item != null) {
      const ani = item.getComponent(AniScript);
      this.ectParent.addChild(item);
      if (ani?.setHandler) {
        ani.setHandler(
          CallBackHandler.pop(() => {
            this.poolFac.push(item);
          }, this)
        );
      } else {
        const spine = item.getComponent(sp.Skeleton);
        spine.setCompleteListener(this.onComplate.bind(this));
        spine.setAnimation(0, 'close', false);
        GameModel.Ins().spineItem = item;
      }

      item.setPosition(retPos);
    }
  }

  onHandler() {
    // const itemScript = GameModel.Ins().spineGrid.getComponent(GridItem);
    // itemScript.setData([new GameColor('-1', ...[0, 1, 2, 3])]);
    // itemScript.bg.active = false;
    // itemScript.refrechColor();
    // this.gridItems.forEach((item) => {
    //   item.selfBtn.active = false;
    // });
    const itemScript = GameModel.Ins().spineGrid.getComponent(GridItem);
    itemScript.bg.active = false;
    itemScript.colorItem.forEach((color) => {
      color.destroyFlag = true;
    });
    this.propCheck('item_box', [itemScript]);
    Tween.stopAllByTarget(GameModel.Ins().spineItem);
    const pos1 = GameModel.Ins().spineItem.getPosition().clone();
    pos1.y += 150;

    const pos2 = pos1.clone();
    pos2.x += pos1.x < 0 ? -view.getVisibleSize().width : view.getVisibleSize().width;

    const func = () => {
      this.poolFac.push(GameModel.Ins().spineItem);
      GameModel.Ins().spineItem = null;
      this.prop1Enable = false;
      EventManager.Ins().emit(EventType.SHOW_MOUSE_CTRL);
    };

    tween(GameModel.Ins().spineItem).to(0.4, { position: pos1 }).delay(0.1).to(0.5, { position: pos2 }, { easing: 'backIn' }).call(func.bind(this)).start();
  }

  onComplate(te: sp.spine.TrackEntry) {
    if (te != null) {
      switch (te.animation.name) {
        case 'close':
          this.onHandler();
          break;
      }
    }
  }

  /** 解锁格子 */
  unlockItem(col: number, row: number) {
    const item = this.getGridItem(col, row);
    // eslint-disable-next-line @typescript-eslint/no-unused-expressions
    item && item.unlockItem();
    this.releaseEnable = false;
    this.actionMove();
  }
}
